package cn.coder.jdbc.mapper;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.coder.jdbc.core.BeanMapping;
import cn.coder.jdbc.util.FieldUtils;
import cn.coder.jdbc.util.ObjectUtils;

public final class QueryResultMapper<T> extends BaseResultMapper<List<T>> {
	private static final Logger logger = LoggerFactory.getLogger(QueryResultMapper.class);

	private final int hash;
	private final Class<T> target;
	private final boolean isPrimitive;
	private BeanMapping tag = null;

	public QueryResultMapper(Class<T> _target, String sql, Object[] array) {
		super(sql, array, false);
		this.target = _target;
		this.isPrimitive = FieldUtils.isPrimitive(_target);
		this.hash = Objects.hash(sql, _target);
	}

	@Override
	public List<T> doPreparedStatement(PreparedStatement stmt) throws SQLException {
		long start = System.currentTimeMillis();
		List<T> list = new ArrayList<>();
		ResultSet rs = stmt.executeQuery();
		int count = 0;
		while (rs.next()) {
			list.add(createBean(rs));
			count++;
		}
		rs.close();
		this.tag = null;
		if (logger.isDebugEnabled())
			logger.debug("Total: {} Time: {}ms", count, (System.currentTimeMillis() - start));
		return list;
	}

	@SuppressWarnings("unchecked")
	private T createBean(ResultSet rs) throws SQLException {
		if (isPrimitive)
			return (T) FieldUtils.toValue(target, rs.getObject(1));

		if (this.tag == null)
			this.tag = getBeanMapping(target, hash, rs.getMetaData());
		return (T) ObjectUtils.createBean(target, rs, tag);
	}

}
